package com.mall.framework.service.impl;

import com.mall.common.constant.CacheConstants;
import com.mall.common.model.UserAuth;
import com.mall.framework.service.CacheService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 缓存服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CacheServiceImpl implements CacheService {

    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public void storeUserToken(Long userId, String token, long expireTime) {
        String key = CacheConstants.USER_TOKEN_PREFIX + userId;
        try {
            redisTemplate.opsForValue().set(key, token, expireTime, TimeUnit.SECONDS);
            log.info("用户Token已存储到Redis，用户ID: {}, 过期时间: {}秒", userId, expireTime);
        } catch (Exception e) {
            log.error("存储用户Token失败，用户ID: {}", userId, e);
            throw new RuntimeException("存储用户Token失败", e);
        }
    }

    @Override
    public String getUserToken(Long userId) {
        String key = CacheConstants.USER_TOKEN_PREFIX + userId;
        try {
            Object value = redisTemplate.opsForValue().get(key);
            return value != null ? value.toString() : null;
        } catch (Exception e) {
            log.error("获取用户Token失败，用户ID: {}", userId, e);
            return null;
        }
    }

    @Override
    public void removeUserToken(Long userId) {
        String key = CacheConstants.USER_TOKEN_PREFIX + userId;
        try {
            redisTemplate.delete(key);
            log.info("用户Token已从Redis删除，用户ID: {}", userId);
        } catch (Exception e) {
            log.error("删除用户Token失败，用户ID: {}", userId, e);
        }
    }

    @Override
    public void addTokenToBlacklist(String token, long expireTime) {
        String key = CacheConstants.TOKEN_BLACKLIST_PREFIX + token;
        try {
            redisTemplate.opsForValue().set(key, "1", expireTime, TimeUnit.SECONDS);
            log.info("Token已加入黑名单，过期时间: {}秒", expireTime);
        } catch (Exception e) {
            log.error("将Token加入黑名单失败", e);
            throw new RuntimeException("将Token加入黑名单失败", e);
        }
    }

    @Override
    public boolean isTokenInBlacklist(String token) {
        String key = CacheConstants.TOKEN_BLACKLIST_PREFIX + token;
        try {
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
            log.error("检查Token黑名单失败", e);
            return false;
        }
    }

    @Override
    public void storeUserInfo(Long userId, UserAuth userAuth, long expireTime) {
        String key = CacheConstants.USER_INFO_PREFIX + userId;
        try {
            redisTemplate.opsForValue().set(key, userAuth, expireTime, TimeUnit.SECONDS);
            log.info("用户信息已存储到Redis，用户ID: {}, 过期时间: {}秒", userId, expireTime);
        } catch (Exception e) {
            log.error("存储用户信息失败，用户ID: {}", userId, e);
            throw new RuntimeException("存储用户信息失败", e);
        }
    }

    @Override
    public UserAuth getUserInfo(Long userId) {
        String key = CacheConstants.USER_INFO_PREFIX + userId;
        try {
            Object value = redisTemplate.opsForValue().get(key);
            return value instanceof UserAuth ? (UserAuth) value : null;
        } catch (Exception e) {
            log.error("获取用户信息失败，用户ID: {}", userId, e);
            return null;
        }
    }

    @Override
    public void removeUserInfo(Long userId) {
        String key = CacheConstants.USER_INFO_PREFIX + userId;
        try {
            redisTemplate.delete(key);
            log.info("用户信息已从Redis删除，用户ID: {}", userId);
        } catch (Exception e) {
            log.error("删除用户信息失败，用户ID: {}", userId, e);
        }
    }

    @Override
    public void refreshTokenExpireTime(Long userId, long expireTime) {
        String key = CacheConstants.USER_TOKEN_PREFIX + userId;
        try {
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            log.info("Token过期时间已刷新，用户ID: {}, 新过期时间: {}秒", userId, expireTime);
        } catch (Exception e) {
            log.error("刷新Token过期时间失败，用户ID: {}", userId, e);
        }
    }

    @Override
    public long getTokenExpireTime(Long userId) {
        String key = CacheConstants.USER_TOKEN_PREFIX + userId;
        try {
            Long expireTime = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            return expireTime != null ? expireTime : -1;
        } catch (Exception e) {
            log.error("获取Token过期时间失败，用户ID: {}", userId, e);
            return -1;
        }
    }

    // ================== 多设备管理 ==================

    @Override
    public void storeUserSession(Long userId, String deviceId, Map<String, Object> sessionInfo, long expireTime) {
        String key = "user_session:" + userId + ":" + deviceId;
        try {
            redisTemplate.opsForValue().set(key, sessionInfo, expireTime, TimeUnit.SECONDS);
            log.info("用户会话已存储，用户ID: {}, 设备ID: {}", userId, deviceId);
        } catch (Exception e) {
            log.error("存储用户会话失败，用户ID: {}, 设备ID: {}", userId, deviceId, e);
        }
    }

    @Override
    public List<Map<String, Object>> getUserSessions(Long userId) {
        String pattern = "user_session:" + userId + ":*";
        try {
            Set<String> keys = redisTemplate.keys(pattern);
            List<Map<String, Object>> sessions = new ArrayList<>();
            if (keys != null) {
                for (String key : keys) {
                    Object value = redisTemplate.opsForValue().get(key);
                    if (value instanceof Map) {
                        sessions.add((Map<String, Object>) value);
                    }
                }
            }
            return sessions;
        } catch (Exception e) {
            log.error("获取用户会话失败，用户ID: {}", userId, e);
            return new ArrayList<>();
        }
    }

    @Override
    public void removeUserSession(Long userId, String deviceId) {
        String key = "user_session:" + userId + ":" + deviceId;
        try {
            redisTemplate.delete(key);
            log.info("用户会话已删除，用户ID: {}, 设备ID: {}", userId, deviceId);
        } catch (Exception e) {
            log.error("删除用户会话失败，用户ID: {}, 设备ID: {}", userId, deviceId, e);
        }
    }

    @Override
    public void removeAllUserSessions(Long userId) {
        String pattern = "user_session:" + userId + ":*";
        try {
            Set<String> keys = redisTemplate.keys(pattern);
            if (keys != null && !keys.isEmpty()) {
                redisTemplate.delete(keys);
                log.info("用户所有会话已删除，用户ID: {}", userId);
            }
        } catch (Exception e) {
            log.error("删除用户所有会话失败，用户ID: {}", userId, e);
        }
    }

    @Override
    public long getUserOnlineDeviceCount(Long userId) {
        String pattern = "user_session:" + userId + ":*";
        try {
            Set<String> keys = redisTemplate.keys(pattern);
            return keys != null ? keys.size() : 0;
        } catch (Exception e) {
            log.error("获取用户在线设备数量失败，用户ID: {}", userId, e);
            return 0;
        }
    }

    // ================== 设备Token映射 ==================

    @Override
    public void storeDeviceToken(Long userId, String deviceId, String token, long expireTime) {
        String key = "device_token:" + userId + ":" + deviceId;
        try {
            redisTemplate.opsForValue().set(key, token, expireTime, TimeUnit.SECONDS);
            log.info("设备Token已存储，用户ID: {}, 设备ID: {}", userId, deviceId);
        } catch (Exception e) {
            log.error("存储设备Token失败，用户ID: {}, 设备ID: {}", userId, deviceId, e);
        }
    }

    @Override
    public String getDeviceToken(Long userId, String deviceId) {
        String key = "device_token:" + userId + ":" + deviceId;
        try {
            Object value = redisTemplate.opsForValue().get(key);
            return value != null ? value.toString() : null;
        } catch (Exception e) {
            log.error("获取设备Token失败，用户ID: {}, 设备ID: {}", userId, deviceId, e);
            return null;
        }
    }

    @Override
    public void removeDeviceToken(Long userId, String deviceId) {
        String key = "device_token:" + userId + ":" + deviceId;
        try {
            redisTemplate.delete(key);
            log.info("设备Token已删除，用户ID: {}, 设备ID: {}", userId, deviceId);
        } catch (Exception e) {
            log.error("删除设备Token失败，用户ID: {}, 设备ID: {}", userId, deviceId, e);
        }
    }

    // ================== 登出统计 ==================

    @Override
    public void recordLogoutEvent(Long userId, Map<String, Object> logoutInfo) {
        String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String key = "logout_stats:" + userId + ":" + date;
        try {
            // 使用Redis的List结构存储登出记录
            redisTemplate.opsForList().rightPush(key, logoutInfo);
            // 设置过期时间为30天
            redisTemplate.expire(key, 30, TimeUnit.DAYS);
            log.info("登出事件已记录，用户ID: {}, 日期: {}", userId, date);
        } catch (Exception e) {
            log.error("记录登出事件失败，用户ID: {}", userId, e);
        }
    }

    @Override
    public Map<String, Object> getLogoutStatistics(Long userId, int days) {
        Map<String, Object> statistics = new HashMap<>();
        int totalLogouts = 0;
        Map<String, Integer> reasonStats = new HashMap<>();
        
        try {
            for (int i = 0; i < days; i++) {
                LocalDateTime date = LocalDateTime.now().minusDays(i);
                String dateStr = date.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                String key = "logout_stats:" + userId + ":" + dateStr;
                
                List<Object> logoutEvents = redisTemplate.opsForList().range(key, 0, -1);
                if (logoutEvents != null) {
                    totalLogouts += logoutEvents.size();
                    
                    // 统计登出原因
                    for (Object event : logoutEvents) {
                        if (event instanceof Map) {
                            Map<String, Object> logoutEvent = (Map<String, Object>) event;
                            String reason = (String) logoutEvent.get("logoutReason");
                            if (reason != null) {
                                reasonStats.put(reason, reasonStats.getOrDefault(reason, 0) + 1);
                            }
                        }
                    }
                }
            }
            
            statistics.put("totalLogouts", totalLogouts);
            statistics.put("reasonStats", reasonStats);
            statistics.put("days", days);
            
        } catch (Exception e) {
            log.error("获取登出统计失败，用户ID: {}", userId, e);
        }
        
        return statistics;
    }
} 